package whendone

/**
  Keeps given commands in history.
  @author Henrik Huttunen
*/
object CommandHistory{
  /** Tracks the browsing of history, pre are the oldest command, current is what selected, post are newest. */ 
  case class History(pre: List[String], current: Option[String], post: List[String])
  
  lazy val emptyHistory: History = History(Nil, None, Nil) 
  
  /** Adds command to the history iff commandHistory's latest is different than command */    
  def addToCommandHistory(commandHistory: History, command: String): History = {
    commandHistory.pre ::: commandHistory.current.toList ::: commandHistory.post match {
      case Nil => History(List(command), None, Nil)
      case nonEmpty => 
        if(nonEmpty.reverse.head == command) commandHistory
        else History(commandHistory.pre ::: commandHistory.current.toList ::: commandHistory.post ::: List(command), None, Nil)
    }
  }
  /** Browses history backwards in time one step. */ 
  def moveBackInCommandHistory(history: History): History = {
    // commands moves => (right) in (pre, current, post)
    val (beforeLast, rightMost) = last(history.pre, (Nil, None))
    History(beforeLast, rightMost, history.current.toList ::: history.post)
  }
  /** Browses history forward in time one step. */
  def moveForwardInCommandHistory(history: History): History = {
    // commands moves <= (left) in (pre, current, post) 
    History(history.pre ::: history.current.toList, head(history.post), tail(history.post))
  }
  /** Returns (allBeforeLast, lastOne) */
  private def last[a](x: List[a], found: (List[a], Option[a])): (List[a], Option[a]) = x match {
    case Nil => found
    case head :: tail => last(tail, (found._1 ::: found._2.toList, Some(head)))
  }
  private def head[a](x: List[a]) = x match {
    case Nil => None
    case head :: tail => Some(head)
  }
  private def tail[a](x: List[a]) = x match {
    case Nil => Nil
    case head :: tail => tail
  }  
}